﻿using SQLinq;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace SimpleDatabaseAdapter
{
    internal class AllDataParser
    {
        internal static string CheckAndGetSQLQuery(ListData list, SQLinqResult querySQLinq, string tableAllData)
        {
            //Ставим правильную таблицу
            querySQLinq.Table = string.Format(SQLPatterns.TABLE_PATTERN, tableAllData);

            //Выставляем SELECT
            if (querySQLinq.Select.Length > 0)
            {
                if (querySQLinq.Select[0] == SQLPatterns.SELECT_ALL_COLUMNS)
                {
                    List<string> columns = new List<string>();

                    AllDataItemAttribute[] attributes = Propertyes.GetAllDataItemAttributes(typeof(AllDataItemBase));
                    foreach (AllDataItemAttribute attr in attributes)
                    {
                        if (!string.IsNullOrEmpty(attr.StaticName))
                        {
                            columns.Add(string.Format(SQLPatterns.COLUMN_PATTERN, attr.StaticName));
                        }
                    }

                    List<ListColumnBase> listColumns = list.GetColumnsData();
                    foreach (ListColumnBase column in listColumns)
                    {
                        columns.Add(string.Format(SQLPatterns.COLUMN_PATTERN, column.AllDataColumnName));
                    }

                    querySQLinq.Select = columns.ToArray();
                }
            }

            //Добавляем ListId
            if (string.IsNullOrEmpty(querySQLinq.Where))
            {
                querySQLinq.Where = string.Format(SQLPatterns.LIST_ID_PATTERN, AllDataColumns.COLUMN_LIST_ID, list.Id);
            }
            else
            {
                querySQLinq.Where = string.Format(SQLPatterns.ADD_LIST_ID_PATTERN, querySQLinq.Where, AllDataColumns.COLUMN_LIST_ID, list.Id);
            }

            string queryStr = AllDataParser.CheckColumns(querySQLinq.ToQuery(), list.GetColumnsData());
            return queryStr;
        }
        internal static string CheckColumns(string query, List<ListColumnBase> listColumns)
        {
            string parseQuery = query;
            string column;
            string allDataColumn;

            foreach (ListColumnBase listColumn in listColumns)
            {
                column = string.Format(SQLPatterns.COLUMN_PATTERN, listColumn.StaticName);
                if (parseQuery.Contains(column))
                {
                    allDataColumn = string.Format(SQLPatterns.COLUMN_PATTERN, listColumn.AllDataColumnName);
                    parseQuery = parseQuery.Replace(column, allDataColumn);
                }
            }

            return parseQuery;
        }
        internal static void CheckColumns(DataTable dt, List<ListColumnBase> listColumns)
        {
            foreach (DataColumn dtColumn in dt.Columns)
            {
                var needListColumns = listColumns.Where(x => x.AllDataColumnName == dtColumn.ColumnName);
                if (needListColumns.Count() > 0)
                {
                    dtColumn.ColumnName = needListColumns.First().StaticName;
                }
            }
        }

        internal static List<T> ReadData<T>(SqlDataReader reader, List<ListColumnBase> listColumns)
        {
            try
            {
                Type itemsType = typeof(T);
                List<T> items = new List<T>();
                ConstructorInfo constructor = itemsType.GetConstructor(new Type[] { });

                if (constructor == null)
                {
                    throw new Exception(string.Format("Class '{0}' not have default constructor.", itemsType));
                }

                DataTable dt = reader.GetSchemaTable();
                IEnumerable<DataRow> dr = dt.AsEnumerable();
                const string columnNameField = "ColumnName";

                while (reader.Read())
                {
                    object item = constructor.Invoke(new object[] { });
                    items.Add((T)item);

                    //Set base propertyes
                    PropertyInfo[] basePropertyes = Propertyes.GetAllDataItemPropertyes(typeof(AllDataItemBase));
                    foreach (PropertyInfo property in basePropertyes)
                    {
                        AllDataItemAttribute attr = property.GetCustomAttribute(typeof(AllDataItemAttribute)) as AllDataItemAttribute;
                        if (!string.IsNullOrEmpty(attr.StaticName))
                        {
                            string columnName = attr.StaticName;
                            if (dr.Where(x => x.Field<string>(columnNameField) == columnName).Count() > 0)
                            {
                                if (reader[columnName] != DBNull.Value)
                                {
                                    property.SetValue(item, Convert.ChangeType(reader[columnName], property.PropertyType), null);
                                }
                            }
                        }
                    }

                    //Set class propertyes
                    PropertyInfo[] propertyes = Propertyes.GetAllDataItemPropertyesNoBase(itemsType);
                    foreach (PropertyInfo property in propertyes)
                    {
                        AllDataItemAttribute attr = property.GetCustomAttribute(typeof(AllDataItemAttribute)) as AllDataItemAttribute;
                        if (!string.IsNullOrEmpty(attr.StaticName))
                        {
                            var needColumns = listColumns.Where(x => x.StaticName == attr.StaticName);
                            if (needColumns.Count() > 0)
                            {
                                string columnName = needColumns.First().AllDataColumnName;
                                if (dr.Where(x => x.Field<string>(columnNameField) == columnName).Count() > 0)
                                {
                                    if (reader[columnName] != DBNull.Value)
                                    {
                                        property.SetValue(item, Convert.ChangeType(reader[columnName], property.PropertyType), null);
                                    }
                                }
                            }
                        }
                    }
                }

                return items;
            }
            finally
            {
                reader.Close();
            }
        }
    }
}
